package com.test.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;

/**
 * Created by jl on 2017/4/28.
 */
public class Server implements Runnable {
    private int port1 = 8099;
    private int port2 = 9099;

    private ServerSocketChannel serverSocket1;
    private ServerSocketChannel serverSocket2;

    private SocketChannel clientChannel1;
    private SocketChannel clientChannel2;

    private Selector selector;

    private ByteBuffer buf = ByteBuffer.allocate(512);

    public Server() {
        init();
    }

    private void init() {
        try {
            selector = SelectorProvider.provider().openSelector();
            // open a channel
            serverSocket1 = ServerSocketChannel.open();
            serverSocket1.configureBlocking(false);
            serverSocket1.socket().bind(new InetSocketAddress("localhost", port1));
            //OP_ACCEPT用于套接字接受操作的操作集位
            serverSocket1.register(selector, SelectionKey.OP_ACCEPT);

            //open another channel
            serverSocket2 = ServerSocketChannel.open();
            serverSocket2.configureBlocking(false);
            serverSocket2.socket().bind(new InetSocketAddress("localhost", port2));
            serverSocket2.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void accept(SelectionKey key) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        if (server.equals(serverSocket1)) {
            clientChannel1 = server.accept();
            clientChannel1.configureBlocking(false);
            //OP_READ用于读取操作的操作集位
            clientChannel1.register(this.selector, SelectionKey.OP_READ);
        } else {
            clientChannel2 = server.accept();
            clientChannel2.configureBlocking(false);
            //OP_READ用于读取操作的操作集位
            clientChannel2.register(this.selector, SelectionKey.OP_READ);
        }
    }

    public void read(SelectionKey key) throws IOException {
        buf.clear();
        SocketChannel channel = (SocketChannel) key.channel();
        int count = channel.read(buf);

        if (count == -1) {
            //取消这个通道的注册
            key.channel().close();
            key.channel();
            return;
        }

        String input = new String(buf.array()).trim();

        if (channel.equals(clientChannel1)) {
            System.out.println("欢迎您使用服务A");
            System.out.println("您的输入为：" + input);
        } else {
            System.out.println("欢迎您使用服务B");
            System.out.println("您的输入为：" + input);
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("running...");
                //选择一组键，其相应的通道已为 I/O 操作准备就绪。
                selector.select();
                //返回此选择器的已选择键集
                Iterator selectorKeys = selector.selectedKeys().iterator();
                while (selectorKeys.hasNext()) {
                    System.out.println("running 2...");
                    SelectionKey key = (SelectionKey) selectorKeys.next();
                    selectorKeys.remove();
                    if (!key.isValid()) {
                        continue;
                    }
                    if (key.isAcceptable()) {
                        accept(key);
                    } else if (key.isReadable()) {
                        read(key);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        Thread thread = new Thread(server);
        thread.start();
    }
}
